//
//  JMCenterManager.m
//  OpenSesame
//
//  Created by zhangjiaming on 17/5/5.
//  Copyright © 2016年 OpenSesame. All rights reserved.
//

#import "JMCenterManager.h"
#import "MBProgressHUD+JM.h"

@interface JMCenterManager() <CBCentralManagerDelegate, CBPeripheralDelegate>
@property (strong, nonatomic) NSTimer *timer;

/** 是否接受完 */
@property (assign, nonatomic, getter=isIntegrity) BOOL integrity;
/** 是否为接受协议头 */
@property (assign, nonatomic, getter=isAgreementHead) BOOL agreementHead;



@property (assign, nonatomic) int16_t checkout; // 接受到的校验位

/** 接收到的命令携带数据长度 */
@property (assign, nonatomic) int dataLength;

/** 接收到完整的数据 */
@property (strong, nonatomic) NSMutableData* receiveDatas;


@end

@implementation JMCenterManager
- (NSMutableArray *)peripherals {
    if (!_peripherals) {
        _peripherals = [NSMutableArray array];
    }
    return _peripherals;
}

+ (instancetype)sharedCenterManager {
    static JMCenterManager *sharedCenterManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedCenterManager = [[JMCenterManager alloc] init];
    });
    return sharedCenterManager;
}

- (instancetype)init {
    if (self = [super init]) {
        self.find = NO;
        _opened = NO;
        _connected = NO;
        _manger = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
        
      //  dispatch_queue_t queue = dispatch_get_main_queue();
        //dispatch_async(queue, ^{
        
            self.timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(scanTimeOver) userInfo:nil repeats:NO];
      //  });
    }
    return self;
}

// 开始扫描
+ (void)beginScan {
    [self sharedCenterManager];
}

// 开始扫描
- (void)beginScan {
    [self.manger scanForPeripheralsWithServices:nil options:nil];
}

// 停止扫描
+ (void)stopScan {
   JMCenterManager *manager = [self sharedCenterManager];
    [manager.peripherals removeAllObjects];
    [manager.manger stopScan];
}

// 连接外设
- (void)connectPeripheral:(CBPeripheral *)peripheral {
    if (self.connectPeripheral != peripheral) {
        self.connectPeripheral = peripheral;
    }
    [self.manger connectPeripheral:peripheral options:nil];
    
}

// 断开与外设的连接
- (void)cancelConnect:(CBPeripheral *)peripheral {
    [self.manger cancelPeripheralConnection:peripheral];
}

// 寻找服务

+ (void)discoveryServices {
    JMCenterManager *mgs = [JMCenterManager sharedCenterManager];
    if (mgs.isConnected) { // 连接状态
        [mgs.connectPeripheral discoverServices:nil];
    } else {
        [MBProgressHUD showError:@"蓝牙未连接"];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral discoverServices:(NSArray *)serverUUIDs {
    peripheral.delegate = self;
    [peripheral discoverServices:serverUUIDs];
}

/**
 *  扫描超时
 */
- (void)scanTimeOver {
    if (!self.find) {
        [MBProgressHUD showError:@"蓝牙连接失败"];
    }
    [self.timer invalidate];
    [self.manger stopScan];
}

#pragma mark - centralManagerDelegate
/**
 *  跟新中心设备状态
 *
 *  @param central 中心设备
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    WDLog(@"JMCenter centralManagerDidUpdateState");
    
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            break;
        case CBCentralManagerStateUnsupported:
            WDLog(@"模拟器不支持蓝牙调试");
            break;
        case CBCentralManagerStateUnauthorized: // 未授权
            break;
        case CBCentralManagerStatePoweredOff:
            WDLog(@"蓝牙处于关闭状态");
            _connected = NO;
            /** 通知代理手机的蓝牙打开与否 */
            if ([self.delegate respondsToSelector:@selector(centerManager:phoneBlueToothIsOpend:)]) {
                [self.delegate centerManager:self phoneBlueToothIsOpend:NO];
            }
            break;
        case CBCentralManagerStateResetting:
            break;
        case CBCentralManagerStatePoweredOn: // 蓝牙打开
             WDLog(@"蓝牙处于打开状态");
            _opened = YES;
            /** 通知代理手机的蓝牙打开与否 */
            if ([self.delegate respondsToSelector:@selector(centerManager:phoneBlueToothIsOpend:)]) {
                [self.delegate centerManager:self phoneBlueToothIsOpend:YES];
            }
            // 扫描外设
            [self.manger scanForPeripheralsWithServices:nil options:nil];
            break;
    }
    
    // 告诉代理手机蓝牙状态
    if ([self.delegate respondsToSelector:@selector(centerManager:didUpdateState:)]) {
        [self.delegate centerManager:self didUpdateState:central];
    }
}

/**
 *  发现外围设备的时候调用
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
   
    WDLog(@"didDiscoverPeripheral %@", peripheral.name);
    // 通知代理新扫描到外设
    if ([self.delegate respondsToSelector:@selector(centerManager:didScanNewPeripheral:WithAdvertisementData:RSSI:)]) {
        [self.delegate centerManager:self didScanNewPeripheral:peripheral WithAdvertisementData:advertisementData RSSI:RSSI];
    }

    // 添加外围设备
    if (![self.peripherals containsObject:peripheral] && peripheral.name != NULL) {
        [self.peripherals addObject:peripheral];
    }
}

/**
 *  连接到某个外设时调用
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    // 停止扫描
    [self.manger stopScan];
    
    if (self.connectPeripheral != peripheral) {
        self.connectPeripheral = peripheral;
    }
    peripheral.delegate = self;
    
    _connected = YES;
    
    [MBProgressHUD showSuccess:@"蓝牙连接成功"];
    
    self.connectPeripheral = peripheral;
    
    // 通知代理连接成功
    if ([self.delegate respondsToSelector:@selector(centerManager:didconnectPeripheral:)]) {
        [self.delegate centerManager:self didconnectPeripheral:peripheral];
    }
}

/**
 *  连接失败调用
 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    [MBProgressHUD showError:@"蓝牙连接失败"];
    self.connectPeripheral = nil;
    [self cleanup];
}

/**
 *  与外设失去连接时调用
 *
 *  @param central    中心设备
 *  @param peripheral 外围设备
 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    [MBProgressHUD showError:@"蓝牙失去连接"];
    _connected = NO;
    
    if ([self.delegate respondsToSelector:@selector(centerManager:didDisconnectPeripheral:)]) {
        [self.delegate centerManager:self didDisconnectPeripheral:peripheral];
    }
}

#pragma mark - CBPeripheralDelegate

// 获取到服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    if (error) {
        NSLog(@"Error discovering services: %@", [error localizedDescription]);
        [self cleanup];
        return;
    }
    for (CBService *service in peripheral.services) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

// 获取到特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    
    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        [self cleanup];
        return;
    }
    for (CBCharacteristic *characteristic in service.characteristics) {

        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF02"]]) {
            // 订阅
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
         
        } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF01"]]) {
            self.characteristic = characteristic;
            // 通知代理向外设发送命令
            if ([self.delegate respondsToSelector:@selector(centerManager:canSendDataWithPeripheral:andCharateristic:)]) {
                _integrity = NO;
                _agreementHead = YES; // 第一次进来的携带协议头
                self.receiveDatas = [[NSMutableData alloc] init];
                [self.delegate centerManager:self canSendDataWithPeripheral:peripheral andCharateristic:characteristic];
            }
        }
    }
}

// 外设特征更新
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    if (error) {
        NSLog(@"Error discovering characteristics: %@", [error localizedDescription]);
        return;
    }

    // 获取发送端命令附加数据长度
    [self.receiveDatas appendData:characteristic.value];
    if (self.receiveDatas.length > 9) { // 此时协议拼接完
        self.receiveOrder = [[self.receiveDatas subdataWithRange:NSMakeRange(7, 1)] convertDataToString];
        self.receiveACK = [self.receiveDatas subdataWithRange:NSMakeRange(8, 1)];
        
        int length = 0;
        [[self.receiveDatas subdataWithRange:NSMakeRange(9, 1)] getBytes:&length length:sizeof(length)];
        self.dataLength = length; 
    }

    // 判断是否接受完整
    if (self.receiveDatas.length == self.dataLength + 12) { // 数据接受完,校验数据
        // 取反校验位
        Byte left = ((Byte *)[self.receiveDatas bytes])[self.receiveDatas.length - 1];
        Byte right = ((Byte *)[self.receiveDatas bytes])[self.receiveDatas.length - 2];
        [self.receiveDatas replaceBytesInRange:NSMakeRange(self.receiveDatas.length - 2, 1) withBytes:&left];
        [self.receiveDatas replaceBytesInRange:NSMakeRange(self.receiveDatas.length - 1, 1) withBytes:&right];
        JMCrc16 *crc = [[JMCrc16 alloc] initWithData:self.receiveDatas andPort:1];
        _agreementHead = YES;
        if (crc.checkout == 0x00) { // 校验正确,通知代理处理外设数据
            if ([self.delegate respondsToSelector:@selector(centerManager:handleReceiveDatas:)]) {
               [self.delegate centerManager:self handleReceiveDatas:self.receiveDatas];
            }
            
        } else { // 错误
            [MBProgressHUD showError:@"数据传输出错"];
        }
        [self.receiveDatas setLength:0];
        self.dataLength = 0;
    }
}

// 外设通知更新
//- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
//    if (error) {
//        NSLog(@"Error changing notification state: %@", error.localizedDescription);
//    }
//    // Exit if it's not the transfer characteristic
//    
//    if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FF02"]]) {
//        
//        return;
//        
//    }
//    
//    
//    
//    // Notification has started
//    
////    if (characteristic.isNotifying) {
////        
////        NSLog(@"Notification began on %@", [characteristic.value bytes]);
////        
////    }
////
//    // Notification has stopped
//    
//    else {
//        
//        // so disconnect from the peripheral
//        
//        NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);
//        
//       // [self.manger cancelPeripheralConnection:peripheral];
//        
//    }
//}

// 外设描述跟新
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error {
    WDLog(@"didUpdateValueForDescriptor%@", descriptor);
}


- (void)cleanup {
    // Don't do anything if we're not connected
    
    if (!self.isConnected) {
        
        return;
        
    }
    
    // See if we are subscribed to a characteristic on the peripheral
    //
    //    if (self.connectPeripheral.services != nil) {
    //
    //        for (CBService *service in self.connectPeripheral.services) {
    //
    //            if (service.characteristics != nil) {
    //
    //                for (CBCharacteristic *characteristic in service.characteristics) {
    //
    //                    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
    //
    //                        if (characteristic.isNotifying) {
    //
    //                            // It is notifying, so unsubscribe
    //
    //                            [self.connectPeripheral setNotifyValue:NO forCharacteristic:characteristic];
    //
    //
    //
    //                            // And we're done.
    //
    //                            return;
    //
    //                        }
    //
    //                    }
    //
    //                }
    //
    //            }
    //
    //        }
    //
    //    }
    
    // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
    [self.manger cancelPeripheralConnection:self.connectPeripheral];
}

@end
